package org.pine.dictionary.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

/**
 * <p>
 * 时间工具类
 * </p>
 *
 * @author pine
 * @since 2024-05-16
 */
public class DateUtils {
    private static final ThreadLocal<Map<String, DateFormat>> DATE_FORMAT_MAP = ThreadLocal.withInitial(HashMap::new);

    public static final String[] NORMAL_PATTERNS = new String[]{"yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd HH:mm:ss,SSS", "yyyy/MM/dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm", "yyyy-MM-dd", "yyyy/MM/dd", "yyyy-MM", "yyyy/MM", "EEE, dd MMM yyyy HH:mm:ss z", "EEE MMM dd HH:mm:ss zzz yyyy", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd'T'HH:mm:ss.SSS", "yyyy-MM-dd'T'HH:mm:ss'Z'", "yyyy-MM-dd'T'HH:mm:ssZ", "yyyy-MM-dd'T'HH:mm:ssXXX", "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", "yyyy-MM-dd'T'HH:mm:ss.SSS'+08:00'"};


    public DateUtils() {
    }

    public static String date2Str(Date date, boolean includeTime) {
        return date2Str(date, includeTime, TimeZone.getDefault());
    }

    public static String date2Str(Date date, boolean includeTime, TimeZone timeZone) {
        return date2Str(date, includeTime, timeZone, Locale.getDefault());
    }

    public static String date2Str(Date date, boolean includeTime, TimeZone timeZone, Locale locale) {
        String pattern = includeTime ? "yyyy-MM-dd HH:mm:ss" : "yyyy-MM-dd";
        return date2Str(date, pattern, timeZone, locale);
    }

    public static String date2Str(Date date, String pattern) {
        return date2Str(date, pattern, TimeZone.getDefault());
    }

    public static String date2Str(Date date, String pattern, TimeZone timeZone) {
        return date2Str(date, pattern, timeZone, Locale.getDefault());
    }

    public static String date2Str(Date date, String pattern, TimeZone timeZone, Locale locale) {
        DateFormat dateFormat = getDateFormat(pattern, locale, timeZone);
        return dateFormat.format(date);
    }

    public static Date str2Date(String str) {
        return str2Date(str, TimeZone.getDefault());
    }

    public static Date str2Date(String str, TimeZone timeZone) {
        return str2Date(str, timeZone, Locale.getDefault());
    }

    public static Date str2Date(String str, TimeZone timeZone, Locale locale) {
        if (str == null) {
            return null;
        } else {
            String[] var3 = NORMAL_PATTERNS;
            int var4 = var3.length;
            int var5 = 0;

            while(var5 < var4) {
                String pattern = var3[var5];

                try {
                    DateFormat dateFormat = getDateFormat(pattern, locale, timeZone);
                    Date date = dateFormat.parse(str);
                    System.out.println(pattern);
                    return date;
                } catch (ParseException var10) {
                    ++var5;
                }
            }

            try {
                long timestamp = Long.parseLong(str);
                return new Date(timestamp);
            } catch (NumberFormatException var9) {
                return null;
            }
        }
    }

    public static Date str2Date(String str, String pattern) throws ParseException {
        return str2Date(str, pattern, TimeZone.getDefault());
    }

    public static Date str2Date(String str, String pattern, TimeZone timeZone) throws ParseException {
        return str2Date(str, pattern, timeZone, Locale.getDefault());
    }

    public static Date str2Date(String str, String pattern, TimeZone timeZone, Locale locale) throws ParseException {
        if (str == null) {
            return null;
        } else {
            DateFormat dateFormat = getDateFormat(pattern, locale, timeZone);
            return dateFormat.parse(str);
        }
    }

    public static LocalDateTime date2LocalDateTime(Date date) {
        return date2LocalDateTime(date, TimeZone.getDefault());
    }

    public static LocalDateTime date2LocalDateTime(Date date, TimeZone timeZone) {
        return LocalDateTime.ofInstant(date.toInstant(), timeZone.toZoneId());
    }

    public static Date localDateTime2Date(LocalDateTime date) {
        return localDateTime2Date(date, TimeZone.getDefault());
    }

    public static Date localDateTime2Date(LocalDateTime date, TimeZone timeZone) {
        Instant instant = date.atZone(timeZone.toZoneId()).toInstant();
        return new Date(instant.getEpochSecond() * 1000L);
    }

    private static DateFormat getDateFormat(String pattern, Locale locale, TimeZone timeZone) {
        String key = pattern + "-" + locale.toLanguageTag() + "-" + timeZone.getID();
        if (((Map)DATE_FORMAT_MAP.get()).containsKey(key)) {
            return (DateFormat)((Map)DATE_FORMAT_MAP.get()).get(key);
        } else {
            DateFormat dateFormat = new SimpleDateFormat(pattern);
            dateFormat.setCalendar(Calendar.getInstance(timeZone, locale));
            ((Map)DATE_FORMAT_MAP.get()).put(key, dateFormat);
            return dateFormat;
        }
    }
}
